/*
 * xenaikcreate.c
 *
 * Publish a data file containing AIK public key, 
 *
 * Format of output file is 4 bytes of AIK public key blob length,
 * big-endian, followed by AIK public key blob;
 *
 * Also outputs a second file containing the TPM_KEY blob for the
 * newly generated AIK.
 */

/*
 * Copyright (c) 2009 Hal Finney
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <trousers/tss.h>
#include <openssl/x509.h>
#include <arpa/inet.h>
#define TPMPASSWD 	"nehalbandi"
#define OWNER_SECRET	"nehalbandi"

#define CKERR	if (result != TSS_SUCCESS) goto error

int
main (int ac, char **av)
{
	TSS_HCONTEXT	hContext;
	TSS_HTPM	hTPM;
	TSS_HKEY	hSRK;
	TSS_HKEY	hAIK;
	TSS_HKEY	hPCA;
	TSS_HPOLICY	hTPMPolicy;
	TSS_HPOLICY	hSrkPolicy;
	TSS_HPOLICY	hAIKPolicy;
	TSS_UUID	SRK_UUID = TSS_UUID_SRK;
	BYTE		n[2048/8];
	FILE		*f_out;
	char		*pass = NULL;
	UINT32		initFlags;
	BYTE		*blob;
	UINT32		blobLen;
	UINT32		tt[1];
	int		i;
	int		result;

	if ((ac<2) || ((0==strcmp(av[1],"-p")) && (ac<3))) {
		fprintf (stderr, "Usage: %s [-p password] outpubfile outaikblobfile\n", av[0]);
		//fprintf (stderr, "Usage: %s [-p password] ekcertfile [certfiles ...] outpubfile outaikblobfile\n", av[0]);
		exit (1);
	}

	if (0 == strcmp(av[1], "-p")) {
		pass = av[2];
		for (i=3; i<ac; i++)
			av[i-2] = av[i];
		ac -= 2;
	}


	result = Tspi_Context_Create(&hContext); CKERR;
	result = Tspi_Context_Connect(hContext, NULL); CKERR;
	result = Tspi_Context_LoadKeyByUUID(hContext,
			TSS_PS_TYPE_SYSTEM, SRK_UUID, &hSRK); CKERR;
	result = Tspi_GetPolicyObject (hSRK, TSS_POLICY_USAGE, &hSrkPolicy); CKERR;
	result = Tspi_Policy_SetSecret(hSrkPolicy, TSS_SECRET_MODE_PLAIN,
			strlen(TPMPASSWD),(BYTE*)TPMPASSWD); CKERR;
	result = Tspi_Context_GetTpmObject (hContext, &hTPM); CKERR;
	result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY,
			TSS_POLICY_USAGE, &hTPMPolicy); CKERR;
	result = Tspi_Policy_AssignToObject(hTPMPolicy, hTPM);
#ifdef OWNER_SECRET
	result = Tspi_Policy_SetSecret (hTPMPolicy, TSS_SECRET_MODE_PLAIN,
			strlen(OWNER_SECRET), (BYTE*)OWNER_SECRET); CKERR;
#else
	result = Tspi_Policy_SetSecret (hTPMPolicy, TSS_SECRET_MODE_POPUP, 0, NULL); CKERR;
#endif

	/* Create dummy PCA key */
	result = Tspi_Context_CreateObject(hContext,
					   TSS_OBJECT_TYPE_RSAKEY,
					   TSS_KEY_TYPE_LEGACY|TSS_KEY_SIZE_2048,
					   &hPCA); CKERR;
	memset (n, 0xff, sizeof(n));
	result = Tspi_SetAttribData (hPCA, TSS_TSPATTRIB_RSAKEY_INFO,
		TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, sizeof(n), n); CKERR;

	/* Create AIK object */
	initFlags = TSS_KEY_TYPE_IDENTITY | TSS_KEY_SIZE_2048;
	if (pass)
		initFlags |= TSS_KEY_AUTHORIZATION;
	result = Tspi_Context_CreateObject(hContext,
					   TSS_OBJECT_TYPE_RSAKEY,
					   initFlags, &hAIK); CKERR;
	if (pass) {
		result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY,
				TSS_POLICY_USAGE, &hAIKPolicy); CKERR;
		result = Tspi_Policy_AssignToObject(hAIKPolicy, hAIK);
		result = Tspi_Policy_SetSecret (hAIKPolicy, TSS_SECRET_MODE_PLAIN,
				strlen(pass)+1, (BYTE*)pass); CKERR;
	}

	/* Generate new AIK */
#ifndef OWNER_SECRET
	{
	/* Work around a bug in Trousers 0.3.1 - remove this block when fixed */
	/* Force POPUP to activate, it is being ignored */
		BYTE *dummyblob1; UINT32 dummylen1;
		if (Tspi_TPM_OwnerGetSRKPubKey(hTPM, &dummylen1, &dummyblob1)
				== TSS_SUCCESS) {
			Tspi_Context_FreeMemory (hContext, dummyblob1);
		}
	}
#endif

	result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hPCA, 0, "",
						 hAIK, TSS_ALG_AES,
						 &blobLen,
						 &blob); CKERR;
	Tspi_Context_FreeMemory (hContext, blob);

	/* Output file with AIK pub key and certs, preceded by 4-byte lengths */
	result = Tspi_GetAttribData (hAIK, TSS_TSPATTRIB_KEY_BLOB,
		TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &blobLen, &blob); CKERR;
	
	if ((f_out = fopen (av[ac-2], "wb")) == NULL) {
		fprintf (stderr, "Unable to open %s for output\n", av[ac-2]);
		exit (1);
	}
	tt[0] = htonl (blobLen);
	fwrite (tt, 1, sizeof(UINT32), f_out);
	fwrite (blob, 1, blobLen, f_out);
	Tspi_Context_FreeMemory (hContext, blob);

	fclose (f_out);

	/* Output file with AIK blob  */
	result = Tspi_GetAttribData (hAIK, TSS_TSPATTRIB_KEY_BLOB,
		TSS_TSPATTRIB_KEYBLOB_BLOB, &blobLen, &blob); CKERR;
	
	if ((f_out = fopen (av[ac-1], "wb")) == NULL) {
		fprintf (stderr, "Unable to open %s for output\n", av[ac-1]);
		exit (1);
	}
	if (fwrite (blob, 1, blobLen, f_out) != blobLen) {
		fprintf (stderr, "Unable to write to %s\n", av[ac-1]);
		exit (1);
	}
	fclose (f_out);
	Tspi_Context_FreeMemory (hContext, blob);

	printf ("Generated AIK!\n");
	return 0;

error:
	printf ("Failure, error code: 0x%x\n", result);
	return 1;
}


